<template>
	<el-container v-loading="isView" class="fm2-container" :class="{ 'view-mode': isView }">
		<el-header height="45px">
			<el-button-group style="margin: 5px;">
				<el-button icon="el-icon-arrow-left" @click="handleUndo">撤回</el-button>
				<el-button icon="el-icon-arrow-right" @click="handleRedo">重做</el-button>
				<el-button icon="el-icon-circle-plus-outline" @click="handleZoom(0.2)">放大</el-button>
				<el-button icon="el-icon-help" @click="handleZoom(0)">还原</el-button>
				<el-button icon="el-icon-remove-outline" @click="handleZoom(-0.2)">缩小</el-button>
				<el-button icon="el-icon-upload2" @click="importXml">导入</el-button>
				<el-upload action="" :before-upload="openBpmn" style="display: none">
					<el-button ref="importBtn" size="mini" icon="el-icon-folder-opened" />
				</el-upload>
				<el-button icon="el-icon-download" @click="handleExportXmlAction">XML</el-button>
				<el-button icon="el-icon-download" @click="handleExportSvgAction">SVG
				</el-button>
				<el-button icon="el-icon-tickets" @click="handlePreviewXml">预览</el-button>
				<el-button icon="el-icon-delete" @click="handleClear">清空</el-button>
				<el-button icon="el-icon-upload" @click="handleSave">保存
				<!-- v-permission="'flowable:model:save,flowable:model:update'" -->
				
				</el-button>
			</el-button-group>
		</el-header>
		<el-main class="fm2-main">
			<el-container class="center-container" style="align-items: stretch;height: 100%;">
				<el-container class="containers">
					<div class="canvas" ref="canvas" />
				</el-container>
				<el-aside class="widget-config-container" style="width: 400px; height: 100%; background-color: #f0f2f5">
					<node-panel v-if="bpmnModel" 
					:bpmnModel="bpmnModel" 
					:modelData="modelData"></node-panel>
				</el-aside>
			</el-container>
		</el-main>
		<el-dialog :visible.sync="xmlVisible" title="预览" fullscreen center>
            <vue-ace-editor v-model="process.xml"
                            @init="editorInit"
                            lang="xml"
                            theme="chrome"
                            width="100%"
                            height="calc(100vh - 214px)"
                            :options="{wrap: true, readOnly: true}">
            </vue-ace-editor>
            <span slot="footer">
           <el-button icon="el-icon-document" type="primary" v-clipboard:copy="process.xml"
                       v-clipboard:success="onCopy">复 制</el-button>
            <el-button icon="el-icon-close" @click="xmlVisible = false">关闭</el-button>
        </span>
        </el-dialog>
	</el-container>
</template>

<script>
	// 汉化
	import translate from './translate/index.js'
	import BpmnModeler from 'bpmn-js/lib/Modeler'
	import defalXml from './resources/newDiagram.js'
	import VueAceEditor from 'vue2-ace-editor'
	import {getProcessModel} from "@/api/process/model.js";
	// import propertiesPanelModule from 'bpmn-js-properties-panel'
	// import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
	// 引入flowable的节点文件
	import flowableModdle from './resources/flowable.json'
	//自定义属性面板
	import NodePanel from './nodePanel/index.vue'
	//
	// import flowableModdleExtension from  './resources/flowable'
	export default {
		name: 'bpmnModel',
		components: {VueAceEditor,NodePanel},
		// 生命周期 - 创建完成（可以访问当前this实例）
		created() {},
		// 生命周期 - 载入后, Vue 实例挂载到实际的 DOM 操作完成，一般在该过程进行 Ajax 交互
		mounted() {
			this.init()
		},
		props: {
			modelData: {
				type: Object,
				default: ()=>({
					id: undefined,
					key: 'processId_1',
					name: 'processName_1',
					description: 'description_1',
					type:undefined,
					documentation:''
				})
			},
			isView: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				scale: 1, //流程图比例（用于放大缩小）
				// bpmn建模器
				bpmnModel: null,
				container: null,
				canvas: null,
				process: {
					xml: '',
					svg: ''
				},
				xmlVisible: false,
				idTest: /^[a-z_][\w-.]*$/i,
				processCategory: [],
				taskCategory: []
			}
		},
		methods: {
			// init ace editor
			editorInit: function () {
			    require('brace/ext/language_tools')
			    require('brace/mode/xml')
			    require('brace/theme/chrome')
			},
			init() {
				// 获取到属性ref为“canvas”的dom节点
				const canvas = this.$refs.canvas
				console.log(2)
				// 建模
				this.bpmnModel = new BpmnModeler({
					container: canvas,
					additionalModules: [
						{
							translate: ['value', translate]
							
						}
					],
					moddleExtensions: {
						flowable: flowableModdle
					}
				})
				
				getProcessModel(this.modelData.key).then(response=>{
					this.createNewDiagram(response.data)
				})
				
			},
			async createNewDiagram(data) {
				// 将字符串转换成图显示出来
				let xml = data.editor||data.result
				if(!xml){
					this.process.xml = defalXml(data.key, data.name, data.category,
					data.description)
				}else{
					xml = xml.replace(/<!\[CDATA\[(.+?)]]>/g, function(match, str) {
					  return str.replace(/</g, '&lt;')
					})
					this.process.xml = xml
				}
				try{
					let { warnings }=await this.bpmnModel.importXML(this.process.xml)
					if (warnings && warnings.length) {
					  warnings.forEach(warn => console.warn(warn));
					}
					// 这里是成功之后的回调, 可以在这里做一系列事情
					this.success();
				}catch(err){
					console.error(err)
					this.msgError("初始化失败："+err)
				}
			},
			// 让图能自适应屏幕
			fitViewport() {
			  this.zoom = this.bpmnModel.get('canvas').zoom('fit-viewport')
			  const bbox = document.querySelector('.fm2-container .viewport').getBBox()
			  const currentViewbox = this.bpmnModel.get('canvas').viewbox()
			  const elementMid = {
			    x: bbox.x + bbox.width / 2 - 65,
			    y: bbox.y + bbox.height / 2
			  }
			  this.bpmnModel.get('canvas').viewbox({
			    x: elementMid.x - currentViewbox.width / 2,
			    y: elementMid.y - currentViewbox.height / 2,
			    width: currentViewbox.width,
			    height: currentViewbox.height
			  })
			  this.zoom = bbox.width / currentViewbox.width * 1.8
			},
			getProcessElement() {
			    return this.bpmnModel.getDefinitions().rootElements[0]
			},
			getProcess() {
			    const element = this.getProcessElement()
			    return {
			        key: element.id,
			        name: element.name,
			        category: element.$attrs['flowable:processCategory']
			    }
			},
			success() {
				this.fitViewport()
				console.log('创建成功!')
			},// 导入
            importXml() {
                this.$refs.importBtn.$el.click()
            },
            // 导入文件选择完成
            openBpmn(file) {
                const reader = new FileReader()
                reader.readAsText(file, 'utf-8')
                reader.onload = () => {
                    this.createNewDiagram(reader)
                }
                return false
            },
            /**
             * 下载xml/svg
             *  @param  type  类型  svg / xml
             *  @param  data  数据
             *  @param  name  文件名称
             */
            download(type, data, name) {
                let dataTrack = ''
                const a = document.createElement('a')
                switch (type) {
                    case 'xml':
                        dataTrack = 'bpmn'
                        break
                    case 'svg':
                        dataTrack = 'svg'
                        break
                    default:
                        break
                }
                name = name || `diagram.${dataTrack}`
                a.setAttribute('href', `data:application/bpmn20-xml;charset=UTF-8,${encodeURIComponent(data)}`)
                a.setAttribute('target', '_blank')
                a.setAttribute('dataTrack', `diagram:download-${dataTrack}`)
                a.setAttribute('download', name)
                document.body.appendChild(a)
                a.click()
                URL.revokeObjectURL(a.href) // 释放URL 对象
                document.body.removeChild(a)
            },
            // 导出XML文件
            async handleExportXmlAction() {
				try{
					const _this = this;
					const { xml } = await this.bpmnModel.saveXML({format: true});
					_this.download('xml', xml, _this.getProcess().name + '.bpmn20.xml');
				}catch(err){
					console.log(err)
					this.msgError("导出错误:"+err)
				}
            },
            // 导出SVG文件
            async handleExportSvgAction() {
				try{
					const _this = this;
					const { svg } = await this.bpmnModel.saveSVG({format: true});
					_this.download('svg', svg, _this.getProcess().name + '.bpmn20.xml');
				}catch(err){
					console.log(err)
					this.msgError("导出错误:"+err)
				}
                // const _this = this
                // this.bpmnModel.saveSVG({format: true}, function (err, svg) {
                //     _this.download('svg', svg, _this.getProcess().name + '.bpmn20.svg')
                // })
            },
            // 预览
           async handlePreviewXml() {
			   try{
			   	const {xml} = await this.bpmnModel.saveXML({format: true})
				this.process.xml = xml
				this.xmlVisible = true
			   }catch(err){
				this.msgError('出现错误'+err)
			   }
                // this.bpmnModel.saveXML({format: true}, (err, xml) => {
                //     this.process.xml = xml
                //     this.xmlVisible = true
                // })
            },
            // 清空
            handleClear() {
                this.createNewDiagram('')
            },
            // 保存
            async handleSave() {
				const _this = this
				try{
					const {xml} = await this.bpmnModel.saveXML({format: true})
					const process = _this.getProcess()
					_this.process.xml = xml
					_this.modelData.editor = xml
					_this.modelData.key = process.key
					_this.modelData.name = process.name
					_this.modelData.category = process.category
					_this.$emit("save", _this.modelData);
				}catch(e){
					this.msgError('出现错误'+err)
				}
				
            },
            // 复制成功
            onCopy() {
                this.$message.success('内容复制成功')
            },
            // 前进
            handleRedo() {
                this.bpmnModel.get('commandStack').redo()
            },
            // 后退
            handleUndo() {
                this.bpmnModel.get('commandStack').undo()
            },
            // 流程图放大缩小
            handleZoom(radio) {
                const newScale = !radio
                    ? 1.0 // 不输入radio则还原
                    : this.scale + radio <= 0.2 // 最小缩小倍数
                        ? 0.2
                        : this.scale + radio
                this.bpmnModel.get('canvas').zoom(newScale)
                this.scale = newScale
            }
		}

	}
</script>

<style lang="scss" scoped>
	/* // 左边工具栏以及编辑节点的样式 */
	@import '~bpmn-js/dist/assets/diagram-js.css';
	@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
	@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
	@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
	/* // 右边工具栏样式 */
	@import '~bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css';
	$primary-color: #409EFF;
	$primary-background-color: #ecf5ff;

	.view-mode {

		.el-header,
		.el-aside,
		.djs-palette {
			display: none;
		}
		.el-loading-mask {
			background-color: initial;
		}
		.el-loading-spinner {
			display: none;
		}
	}

	.fm2-container {
		background: #fff;
		height: calc(100vh - 84px);
		border: 1px solid #e0e0e0;

		.el-container {
			height: 100% !important;
		}

		&>.el-container {
			background: #fff;
		}

		.fm2-main {
			position: relative;
			border-top: solid 1px #e4e7ed;

			&>.el-container {
				position: absolute;
				top: 0;
				bottom: 0;
				left: 0;
				right: 0;
			}
		}

		footer {
			height: 30px;
			line-height: 30px;
			border-top: 1px solid #e0e0e0;
			font-size: 12px;
			text-align: right;
			color: $primary-color;
			background: #fafafa;

			a {
				color: $primary-color;
			}
		}
	}

	.center-container {
		border-left: 1px solid #e0e0e0;
		border-right: 1px solid #e0e0e0;
	}

	.widget-config-container {
	    box-sizing: border-box;
	    padding: 0 8px;
	    border-left: 1px solid #eeeeee;
	    box-shadow: 0 0 8px #cccccc;
	    max-height: 100%;
	    // overflow-y: scroll;
	
	    .el-form-item__label {
	        font-size: 13px;
	    }
	}

	.containers {
		background-color: #ffffff;
		width: 100%;
		height: 100%;

		.canvas {
			width: 100%;
			height: 100%;
		}

		.bjs-powered-by {
			display: none;
		}
	}
</style>
